﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.IO;

using MEFedMVVM.ViewModelLocator;
using Cinch;
using System.Configuration;
using System.Threading;

namespace Anata.Client
{

    /// <summary>
    /// Runtime implementation of the 
    /// Data service used by the <c>ImageLoaderViewModel</c> to obtain data
    /// </summary>
    [PartCreationPolicy(CreationPolicy.NonShared)]
    [ExportService(ServiceType.Runtime, typeof(IKonsumenProvider))]
    public class KonsumenProvider : IKonsumenProvider
    {
        #region Data
        private BackgroundTaskManager<int, List<Konsumen>> multiFetchBgWorker =
            new BackgroundTaskManager<int, List<Konsumen>>();
        private BackgroundTaskManager<int, Konsumen> singleFetchBgWorker =
            new BackgroundTaskManager<int, Konsumen>();
        private BackgroundTaskManager<Konsumen, Konsumen> singleUpdateBgWorker =
            new BackgroundTaskManager<Konsumen, Konsumen>();



        private BackgroundTaskManager<int, List<KonsumenThumbnailViewModel>> multiFetchTVMBgWorker =
            new BackgroundTaskManager<int, List<KonsumenThumbnailViewModel>>();
        private BackgroundTaskManager<KonsumenThumbnailViewModel, KonsumenThumbnailViewModel> singleUpdateTVMBgWorker =
            new BackgroundTaskManager<KonsumenThumbnailViewModel, KonsumenThumbnailViewModel>();
        private BackgroundTaskManager<KonsumenViewModel, KonsumenViewModel> singleUpdateVMBgWorker =
            new BackgroundTaskManager<KonsumenViewModel, KonsumenViewModel>();
        #endregion



        #region PublicProperties
        public void LazyFetchKonsumens(int page, Action<List<Konsumen>> callback)
        {
            BackgroundTaskManager<int, List<Konsumen>> bgWorker = null;
            if (multiFetchBgWorker.TaskFunc != null)
            {
                bgWorker = new BackgroundTaskManager<int, List<Konsumen>>();
            }
            else
            {
                bgWorker = multiFetchBgWorker;
            }

            bgWorker.TaskFunc = (argument) =>
                {
                    return FetchKonsumensInternal(argument);
                };

            bgWorker.CompletionAction = (result) =>
                {
                    callback(result);
                };

            bgWorker.WorkerArgument = page;
            bgWorker.RunBackgroundTask();

        }
        public void LazyFetchKonsumen(int idKonsumen, Action<Konsumen> callback)
        {
            BackgroundTaskManager<int, Konsumen> bgWorker = null;
            if (singleFetchBgWorker.TaskFunc != null)
            {
                bgWorker = new BackgroundTaskManager<int, Konsumen>();
            }
            else
            {
                bgWorker = singleFetchBgWorker;
            }

            bgWorker.TaskFunc = (argument) =>
            {
                return FetchKonsumenInternal(argument);
            };

            bgWorker.CompletionAction = (result) =>
            {
                callback(result);
            };

            bgWorker.WorkerArgument = idKonsumen;
            bgWorker.RunBackgroundTask();

        }
        public void LazyUpdateKonsumen(Konsumen pKonsumen, Action<Konsumen> callback)
        {
            BackgroundTaskManager<Konsumen, Konsumen> bgWorker = null;
            if (singleUpdateBgWorker.TaskFunc != null)
            {
                bgWorker = new BackgroundTaskManager<Konsumen, Konsumen>();
            }
            else
            {
                bgWorker = singleUpdateBgWorker;
            }

            bgWorker.TaskFunc = (argument) =>
            {
                return UpdateKonsumenInternal(argument);
            };

            bgWorker.CompletionAction = (result) =>
            {
                callback(result);
            };

            bgWorker.WorkerArgument = pKonsumen;
            bgWorker.RunBackgroundTask();

        }

        public void LazyFetchKonsumens(int page, Action<List<KonsumenThumbnailViewModel>> callback)
        {
            BackgroundTaskManager<int, List<KonsumenThumbnailViewModel>> bgWorker = null;
            if (multiFetchTVMBgWorker.TaskFunc != null)
            {
                bgWorker = new BackgroundTaskManager<int, List<KonsumenThumbnailViewModel>>();
            }
            else
            {
                bgWorker = multiFetchTVMBgWorker;
            }

            bgWorker.TaskFunc = (argument) =>
            {
                return FetchKonsumenTVMsInternal(argument);
            };

            bgWorker.CompletionAction = (result) =>
            {
                callback(result);
            };

            bgWorker.WorkerArgument = page;
            bgWorker.RunBackgroundTask();

        }
        #endregion

        #region PublicProperties
        /// <summary>
        /// To allow this class to be unit tested stand alone
        /// See CinchV1 articles about Unit Testing for this
        /// Or comments in Cinch BackgroundTaskManager<T> class
        /// </summary>
        public BackgroundTaskManager<int, List<Konsumen>> MultiFetchBgWorker
        {
            get { return multiFetchBgWorker; }
        }
        public BackgroundTaskManager<int, Konsumen> SingleFetchBgWorker
        {
            get { return singleFetchBgWorker; }
        }
        public BackgroundTaskManager<Konsumen, Konsumen> SingleUpdateBgWorker
        {
            get { return singleUpdateBgWorker; }
        }

        #endregion

        #region Private Methods
        private List<Konsumen> FetchKonsumensInternal(int page)
        {
            List<Konsumen> konsumens = new List<Konsumen>();
            //TODO: bener-bener konek ke database
            int pageSize = Int32.Parse(ConfigurationManager.AppSettings["LazyLoadPageSize"].ToString());
            using (AnataEntities context = new AnataEntities())
            {
                IQueryable<Konsumen> konsumenQuery =
                    from konsumen in context.Konsumen
                    orderby konsumen.Nama
                    select konsumen;
                konsumens = konsumenQuery.Skip(page * pageSize).Take(pageSize).ToList();
            }
            return konsumens;
        }
        private Konsumen FetchKonsumenInternal(int idKonsumen)
        {
            Konsumen retval = new Konsumen();
            using (AnataEntities context = new AnataEntities())
            {
                IQueryable<Konsumen> konsumenQuery =
                    from konsumen in context.Konsumen
                    orderby konsumen.Nama
                    where konsumen.IdKonsumen == idKonsumen
                    select konsumen;
                retval = konsumenQuery.First();
            }
            return retval;
        }
        private Konsumen UpdateKonsumenInternal(Konsumen pKonsumen)
        {
            using (AnataEntities context = new AnataEntities())
            {
                if (pKonsumen.IdKonsumen == 0)
                {
                    context.AddToKonsumen(pKonsumen);
                }
                else
                {
                    context.Attach(pKonsumen);
                    // If the SalesOrderDetailID is not 0, then the item is not new
                    // and needs to be updated. Because we already added the 
                    // updated object to the context we need to apply the original values.
                    // If we attached originalItem to the context 
                    // we would need to apply the current values:
                    // context.ApplyCurrentValues("SalesOrderDetails", updatedItem);
                    // Applying current or original values, changes the state 
                    // of the attached object to Modified.
                    context.ObjectStateManager.ChangeObjectState(pKonsumen, System.Data.EntityState.Modified);
                }
                context.SaveChanges();
            }
            return pKonsumen;
        }

        private List<KonsumenThumbnailViewModel> FetchKonsumenTVMsInternal(int page)
        {
            List<KonsumenThumbnailViewModel> retval = new List<KonsumenThumbnailViewModel>();
            KonsumenThumbnailViewModel tempKTVM = null;
            try
            {
                int pageSize = Int32.Parse(ConfigurationManager.AppSettings["LazyLoadPageSize"].ToString());
                using (AnataEntities context = new AnataEntities())
                {
                    var query = from konsumen in context.Konsumen
                                orderby konsumen.Nama
                                select konsumen;
                    foreach (var konsumen in query.Skip(page * pageSize).Take(pageSize).ToList())
                    {
                        tempKTVM = new KonsumenThumbnailViewModel();
                        SynchKonsumenToKTVM(konsumen, tempKTVM);
                        retval.Add(tempKTVM);
                    }
                }
            }
            catch (Exception) { }
            return retval;
        }
        #endregion

        #region PrivateMethods
        private void SynchKonsumenToKTVM(Konsumen original, KonsumenThumbnailViewModel ktvm)
        {
            ktvm.IdKonsumen = original.IdKonsumen;
            ktvm.Nama = original.Nama;
            ktvm.Alamat = original.Alamat;
            ktvm.Telepon = original.NoTelepon;
            ktvm.JenisKelamin = original.JenisKelamin;
            ktvm.TanggalLahir = original.TanggalLahir;
        }
        #endregion
    }
}
